﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using Graphe.Collations.Commands;

namespace Graphe.Collations
{
    public class Collation : IComparable<Collation>
    {
        #region Constructor

        public Collation()
        {
            Verses = new VerseCollection();
            Manuscripts = new List<string>();
        }

        #endregion
        #region Private Instance Fields

        private Stack<Command> _commands = new Stack<Command>();
        private Stack<Command> _undoneCommands = new Stack<Command>();

        #endregion
        #region Public Properties

        public string Title { get; set; }
        public string HeaderText { get; set; }
        public List<string> Manuscripts { get; set; }
        public VerseCollection Verses { get; set; }

        #endregion

        public void Load(string path)
        {
            using (FileStream stream = new FileStream(path, FileMode.Open))
            {
                Load(stream);
            }
        }

        public void Load(Stream stream)
        {
            using (XmlTextReader reader = new XmlTextReader(stream))
            {
                reader.ReadToFollowing("Verses");

                CollationDebugMessages debugMessages = new CollationDebugMessages();

                Verses = new VerseCollection();
                Verses.Parse(reader, debugMessages);
            }
        }

        public void Save(string path)
        {

            using (XmlTextWriter writer = new XmlTextWriter(path, System.Text.Encoding.Unicode))
            {
                writer.WriteStartElement("Collation");
                {
                    writer.WriteStartElement("Header");
                    {
                        writer.WriteStartElement("Title");
                        writer.WriteString(Title);
                        writer.WriteEndElement();

                        writer.WriteStartElement("HeaderText");
                        writer.WriteString(HeaderText);
                        writer.WriteEndElement();

                        writer.WriteStartElement("Manuscripts");

                        foreach (string manuscript in Manuscripts)
                        {
                            writer.WriteStartElement("Manuscript");
                            writer.WriteString(manuscript);
                            writer.WriteEndElement();
                        }

                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();




                    writer.WriteStartElement("Verses");
                    foreach (Verse verse in Verses)
                    {
                        verse.Render(writer);
                    }
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }

            //TODO: Remove at some point. This is just to reformat the file for ease of viewing by the human eye.
            XmlDocument doc = new XmlDocument();
            doc.Load(path);
            doc.Save(path);
        }

        #region IComparable<Collation> Members

        public int CompareTo(Collation other)
        {
            foreach (Verse verse in Verses)
            {
                bool foundMatch = false;

                foreach (Verse verse2 in other.Verses)
                {
                    if (verse.CompareTo(verse2) == 0)
                    {
                        foundMatch = true;
                        break;
                    }
                }

                if (!foundMatch)
                    return -1;
            }

            foreach (Verse verse in other.Verses)
            {
                bool foundMatch = false;

                foreach (Verse verse2 in Verses)
                {
                    if (verse.CompareTo(verse2) == 0)
                    {
                        foundMatch = true;
                        break;
                    }
                }

                if (!foundMatch)
                    return -1;
            }

            return 0;
        }

        #endregion
        #region Undo/Redo Implementation

        public void Do(Command command)
        {
            if (_undoneCommands.Count > 0)
                _undoneCommands.Clear();

            _commands.Push(command);
            command.Execute();
        }

        public void Undo()
        {
            Command command = _commands.Pop();

            if (command != null)
            {
                command.Undo();
                _undoneCommands.Push(command);
            }
        }

        public void Redo()
        {
            Command command = _undoneCommands.Pop();

            if(command != null)
                command.Execute();
        }

        #endregion
    }
}
